﻿Shader "NumbFish/UI/CodeRain" {
    Properties {
        [HideInInspector] [PerRendererData] _MainTex("Sprite Texture", 2D) = "white"{}
        [HideInInspector] _Color("Tint", Color) = (1, 1, 1, 1)
        [HideInInspector] _StencilComp("Stencil Comparison", Float) = 8
        [HideInInspector] _Stencil("Stencil ID", Float) = 0
        [HideInInspector] _StencilOp("Stencil Operation", Float) = 0
        [HideInInspector] _StencilWriteMask("Stencil Write Mask", Float) = 255
        [HideInInspector] _StencilReadMask("Stencil Read Mask", Float) = 255
        [HideInInspector] _ColorMask("Color Mask", Float) = 15
        [HideInInspector] [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0

        // 代码图片
        [NoScaleOffset] _CodeTex("Code Tex", 2D) = "black"{}

        // 代码雨颜色
        [HDR] _CodeColor("Code Rain Color", Color) = (2, 16, 0, 1)

        // 代码图片缩放控制
        // xy: 图片缩放, zw: 未使用
        _Scale("Code Tex Scale", Vector) = (2, 1, 0, 0)

        // 代码图片行列数, 层数, 深度定义
        // x: 列数, y: 行数, z: 层数, w: 深度
        _Size("Code Tex Size", Vector) = (7, 9, 4, 7.5)

        // 代码雨速度控制
        // x: 文本下落速度, y: 颜色下落速度, z: 放大速度, w: 未使用
        _Speed("Code Rain Speed Ctrl", Vector) = (1, 1, 0.1, 0)

        // xy负责代码雨透明度随深度变化的控制, 深度d变化范围_Size.w ~ 0, 公式: max(0, 1 - x * abs(y - d))
        // z负责代码雨显示长度控制, 控制了透明度a, 公式: a = pow(a, z)
        // x: 透明度变化速度, y: 透明度为1时的深度值, z: 代码雨显示长度控制, w: 未使用
        _AlphaCtrl("Code Rain Alpha Ctrl", Vector) = (0.5, 2, 10, 0)

        // 代码雨随机种子
        // x: 控制水平方向, y: 控制垂直方向, zw: 未使用
        _RandomSeed("Code Rain Random Seed", Vector) = (114.514, 191.9810, 0, 0)
    }

    SubShader {
        Tags {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
            "PreviewType" = "Plane"
            "CanUseSpriteAtlas" = "True"
        }

        Stencil {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend One OneMinusSrcAlpha
        ColorMask [_ColorMask]

        Pass {
            Name "Default"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0
            #include "UnityCG.cginc"
            #include "UnityUI.cginc"
            #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
            #pragma multi_compile_local _ UNITY_UI_ALPHACLIP

            struct appdata {
                float4 vertex : POSITION;
                float4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                float4 worldPosition : TEXCOORD1;
                float4 mask : TEXCOORD2;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            sampler2D _CodeTex;
            float2 _Scale;
            float4 _Size;
            float4 _CodeColor;
            float4 _Speed;
            float4 _AlphaCtrl;
            float4 _RandomSeed;
            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            float4 _ClipRect;
            float4 _MainTex_ST;
            float _UIMaskSoftnessX;
            float _UIMaskSoftnessY;

            v2f vert(appdata input) {
                v2f output;
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
                float4 vPosition = UnityObjectToClipPos(input.vertex);
                output.worldPosition = input.vertex;
                output.vertex = vPosition;
                float2 pixelSize = vPosition.w;
                pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));
                float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
                float2 maskUV = (input.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
                output.texcoord = TRANSFORM_TEX(input.texcoord.xy, _MainTex);
                output.mask = float4(input.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy)));
                output.color = input.color * _Color;
                return output;
            }

            float4 CodeRain(float2 uv, float t) {
                // 放大缩小
                float baseT = _Time.y * -_Speed.z + t;
                float floorT = floor(baseT);
                float fracT = frac(baseT);
                float deep = fracT * _Size.w;
                uv = (uv - 0.5) * _Scale * deep + 0.5;
                uv.x += sin(_RandomSeed.x * floorT);
                uv.y += _Time.y * _Speed.x;
                float4 codeTex = tex2D(_CodeTex, frac(uv));
                float alpha = max(0, 1 - _AlphaCtrl.x * abs(_AlphaCtrl.y - deep));

                // 条纹落下
                float stripe = floor(uv.x * _Size.x);
                float y = 0.5 * (sin(_RandomSeed.y * stripe) + 1);
                alpha *= pow(frac(1 - uv.y + y - _Time.y * _Speed.y), _AlphaCtrl.z);

                return codeTex * codeTex.a * alpha * _CodeColor;
            }

            fixed4 frag(v2f input) : SV_Target {
                half2 uv = input.texcoord;

                half4 output = input.color * (tex2D(_MainTex, uv) + _TextureSampleAdd);

                #ifdef UNITY_UI_CLIP_RECT
                half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(input.mask.xy)) * input.mask.zw);
                output.a *= m.x * m.y;
                #endif

                #ifdef UNITY_UI_ALPHACLIP
                clip(output.a - 0.001);
                #endif

                for (float i = 0; i < _Size.z; ++i) {
                    output += CodeRain(uv, i / _Size.z);
                }

                output.rgb *= output.a;
                return output;
            }
            ENDCG
        }
    }
}
